#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>

using namespace std;

class Solution1 {
public:
    int kthLargestValue(vector<vector<int>>& matrix, int k) {
        int n = matrix.size(); int m = matrix[0].size();
        vector<vector<int>> pre(n + 1, vector<int>(m + 1));
        priority_queue<int, vector<int>, greater<>> pq;
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
            {
                pre[i][j] = pre[i - 1][j] ^ pre[i][j - 1] ^ pre[i - 1][j - 1] ^ matrix[i - 1][j - 1];
                if (pq.size() < k)
                {
                    pq.push(pre[i][j]);
                }
                else if (pq.top() < pre[i][j])
                {
                    pq.pop();
                    pq.push(pre[i][j]);
                }
            }
        return pq.top();
    }
};

struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(nullptr) {}
};
 
class Solution2 {
public:

    ListNode* merge(vector<ListNode*>& lists, int l, int r)
    {
        if (l > r || l > lists.size()) return nullptr;
        if (l == r) return lists[l];

        int m = (l + r) >> 1;
        ListNode* left = merge(lists, l, m);
        ListNode* right = merge(lists, m + 1, r);

        auto res = ListNode(-1);
        ListNode* tail = &res;
        while (left && right)
        {
            if (right->val < left->val)
            {
                tail->next = right;
                right = right->next;
            }
            else
            {
                tail->next = left;
                left = left->next;
            }
            tail = tail->next;
        }
        if (left) tail->next = left;
        if (right) tail->next = right;

        return res.next;
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if (lists.size() == 0) return nullptr;
        return merge(lists, 0, lists.size() - 1);
    }
};

#include <cstring>

int n, m;
int memo[101][101];
int dx[4] = { 0,0,-1,1 };
int dy[4] = { -1,1,0,0 };

int dfs(vector<vector<int>>& martix, int i, int j)
{
    if (memo[i][j] != 0) return memo[i][j];

    int res = 0;
    for (int k = 0; k < 4; ++k)
    {
        int x = i + dx[k]; int y = j + dy[k];
        if (x >= 0 && y >= 0 && x < n && y < m && martix[i][j] > martix[x][y])
            res = max(res, dfs(martix, x, y));
    }
    return memo[i][j] = res + 1;
}

int main()
{
    memset(memo, 0, sizeof(memo));
    cin >> n >> m;
    vector<vector<int>> martix(n, vector<int>(m));
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < m; ++j)
            cin >> martix[i][j];
    int res = 0;
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < m; ++j)
            res = max(res, dfs(martix, i, j));

    cout << res;

    return 0;
}